home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockRichDNDService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
33KB
|
1,006 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
const CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;
Components.utils.import("resource:///modules/FlockXPCOMUtils.jsm");
FlockXPCOMUtils.debug = false;
const MODULE_NAME = "Flock Rich Drag and Drop Service";
// The Rich Drag&Drop service
const FLOCK_RICHDRAGDROP_SERVICE_CLASS_NAME
= "Flock Rich Drag and Drop Service";
const FLOCK_RICHDRAGDROP_SERVICE_CLASS_ID
= Components.ID("{30b8dc92-abe0-44ee-a845-e1a827d59610}");
const FLOCK_RICHDRAGDROP_SERVICE_CONTRACT_ID = "@flock.com/rich-dnd-service;1";
const FLOCK_PREF_SERVICE_CONTRACT_ID = "@mozilla.org/preferences-service;1";
const FLOCK_CATEGORY_MANAGER_CONTRACT_ID = "@mozilla.org/categorymanager;1";
const FLOCK_RICH_CONTENT_CATEGORY_ENTRY = "flockRichContentHandler";
const FLOCK_BREADCRUMB_ID = "flock-breadcrumb";
const FLAVOR_UNICODE = "text/unicode";
const FLAVOR_HTML = "text/html";
const FLAVOR_MOZ_URL = "text/x-moz-url";
const FLAVOR_FLOCK_MEDIA = "text/x-flock-media";
const FLAVOR_TEXT_CITE = "text/x-flock-textcitation";
const FLAVOR_HTML_CITE = "text/x-flock-htmlcitation";
const FLAVOR_MOZ_RDF = "moz/rdfitem";
// From viewPartialSource.js
//
// These are markers used to delimit the selection during processing. They
// are removed from the final rendering, but we pick space-like characters for
// safety (and futhermore, these are known to be mapped to a 0-length string
// in transliterate.properties). It is okay to set start=end, we use findNext()
// U+200B ZERO WIDTH SPACE
const MARK_SELECTION_START = "\u200B\u200B\u200B\u200B\u200B";
const MARK_SELECTION_END = "\u200B\u200B\u200B\u200B\u200B";
const NS_XHTML = "http://www.w3.org/1999/xhtml";
var _logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
_logger.init("flockRichDragDropService");
/**************************************************************************
* Component: Flock Rich Drag and Drop Service
**************************************************************************/
// Constructor.
function flockRichDragDropService() {
}
/**************************************************************************
* Flock Rich Drag and Drop Service: XPCOM Component Creation
**************************************************************************/
flockRichDragDropService.prototype = new FlockXPCOMUtils.genericComponent(
FLOCK_RICHDRAGDROP_SERVICE_CLASS_NAME,
FLOCK_RICHDRAGDROP_SERVICE_CLASS_ID,
FLOCK_RICHDRAGDROP_SERVICE_CONTRACT_ID,
flockRichDragDropService,
CI.nsIClassInfo.SINGLETON,
[
CI.flockIRichDNDService
]
);
// FlockXPCOMUtils.genericComponent() registration callbacks.
flockRichDragDropService.prototype.register =
function flockRichDragDropService_register(aCompMgr, aFileSpec, aLocation, aType) {
}
flockRichDragDropService.prototype.unregister =
function flockRichDragDropService_unregister(aCompMgr, aFileSpec, aLocation, aType) {
}
/**************************************************************************
* Flock Rich Drag and Drop Service: flockIRichDNDService Implementation
**************************************************************************/
flockRichDragDropService.prototype.getRichSelection =
function fRDDS_getRichSelection(aSession) {
var node = aSession.sourceNode;
// Dragging from outside the browser
if (!node) {
return null;
}
// Gather some information about the current window, as it can be used
// to enrich the data we will be sending
var wm = CC["@mozilla.org/appshell/window-mediator;1"]
.getService(CI.nsIWindowMediator);
var top = wm.getMostRecentWindow("navigator:browser");
var contentElement = top.document.getElementById("content");
var topUrl = contentElement.contentDocument.URL;
var topTitle = contentElement.contentTitle;
if (topTitle.length == 0) {
topTitle = contentElement.contentDocument.location;
}
if (topUrl && topUrl.match(/^chrome:\/\/.+/)) {
// Never mark content with a chrome URL, as it is likely to be send
// to someone or published online
topUrl = "";
}
var nodeName = node.nodeName.toLowerCase();
_logger.debug("nodeName="+nodeName);
// HTML image from a web page
if (nodeName == "img") {
var imageTitle = "";
if (node.title) {
imageTitle = node.title;
} else if (node.alt) {
imageTitle = node.alt;
}
var imageURL = this._makeURLAbsolute(topUrl, node.src);
// Don't insert a stupid image containing Javascript
if (imageURL.match("javascript:")) {
return null;
}
if (imageURL == topUrl) {
// Bug 3756, when the image alone is displayed in the browser
// Mozilla is replacing the "alt" tag by "This image contains error"
// a clever hack, but we don't want to use that for the title
imageTitle = imageURL.split("/").pop();
}
return this._getImageTransferable(imageURL, imageTitle, topUrl);
}
// The URL bar favicon: appear as a XUL image but must be treated as a link
if ((nodeName == "image") || (nodeName == "xul:image")) {
return this._getLinkTransferable(topUrl, topTitle);
}
// Browser tab: to be sent as a link
if ((nodeName == "tab") || (nodeName == "xul:tab")) {
var tabUrl = top.content.document.location.toString();
var tabTitle = node.label;
return this._getLinkTransferable(tabUrl, tabTitle);
}
// Mediabar
if ((nodeName == "photo") || (nodeName == "xul:photo")) {
return this._getMediabarTransferable(node, topUrl);
}
// Do not support these
if ((nodeName == "shelficon") || (nodeName == "richtreefolder")) {
return null;
}
// Deal with a selection
var selection = top.getSelection();
if (selection.toString().length > 0) {
return this._getSelectionTransferable(topUrl, topTitle, selection);
}
// If we don't find a SRC or HREF tag in this node, then it is most likely an
// inline element, so we will traverse through its ancestors until we find
// something we can use.
while (node && node != contentElement.contentDocument.body) {
if (node.src) {
// If it is an img, make sure the src attribute is the full path
node.setAttribute("src", node.src);
var imageURL = node.src;
var imageTitle = node.src;
if (node.getAttribute("title")) {
imageTitle = node.getAttribute("title");
} else if (node.getAttribute("alt")) {
imageTitle = node.getAttribute("alt");
}
return this._getImageTransferable(imageURL, imageTitle, topUrl);
}
if (node.href) {
// If it is a link make sure the href attribute is the full path
node.setAttribute("href", node.href);
return this._getLinkTransferable(node.href, node.textContent);
}
// Look at parent
node = node.parentNode;
}
// Don't know... we can return a link to the page
return this._getLinkTransferable(topUrl, topTitle);
}
flockRichDragDropService.prototype.getMessageFromTransferable =
function fRDDS_getMessageFromTransferable(aSubject, aListSize, aFlavorList)
{
var message = {};
// Get transferable's available flavors
var transFlavors = aSubject.flavorsTransferableCanExport();
// Build string array of flavors for easy compare
var transFlavorArray = [];
for (var i = 0; i < transFlavors.Count(); i++) {
transFlavorArray[i] = transFlavors.GetElementAt(i)
.QueryInterface(CI.nsISupportsCString)
.data;
}
// Go through list of desired flavors
for (var i = 0; i < aListSize; i++) {
// Is this flavor available in the transferable?
var flavor = aFlavorList[i];
if (transFlavorArray.indexOf(flavor) != -1) {
// It is -- try to build a message using it
message = this._getMessageFromTransferableWithFlavor(aSubject, flavor);
if (message.body) {
// Successfully built a message from this transferable
return message;
}
}
}
// None of the desired flavors are available in the transferable. If it has a
// flavor we support, use it instead.
for (var i = 0; i < transFlavorArray.length; i++) {
// Get a flavor from the transferable
var flavor = transFlavorArray[i];
// Try to build a message using it
message = this._getMessageFromTransferableWithFlavor(aSubject, flavor);
if (message.body) {
// Successfully built a message from this transferable
return message;
}
}
// No valid flavor available
_logger.debug("Could not find a supported flavor.");
// We should do something to support it
throw "No Supported Flavour for Sharing";
}
flockRichDragDropService.prototype.getBreadcrumb =
function fRDDS_getBreadcrumb(aType)
{
var breadcrumb = "";
// Is breadcrumb enabled?
var prefService = CC[FLOCK_PREF_SERVICE_CONTRACT_ID]
.getService(CI.nsIPrefBranch);
if (prefService.getPrefType("flock.sharing.breadcrumb.enabled")
&& prefService.getBoolPref("flock.sharing.breadcrumb.enabled"))
{
var footer = flockGetString("common/sharing", "flock.sharing.breadcrumb.footer1");
var url = flockGetString("common/sharing", "flock.sharing.breadcrumb.url");
// Build breadrcumb based on desired type of formatting
if (aType == "rich") {
breadcrumb = "<br /><br />" + footer + "<br />"
+ "<a href='" +url + "'>" + url + "</a>" + "<br />";
} else {
// aType == "plain"
breadcrumb = "\n\n" + footer + "\n" + url + "\n";
}
}
return breadcrumb;
}
flockRichDragDropService.prototype.handleDrop =
function frDDS_handleDrop(aSession, aTargetElement) {
var type = aTargetElement.localName.toLowerCase();
if (type == "textarea") {
if (this._handleDropToTextArea(aSession, aTargetElement)) {
return true;
}
} else if (this._isInRichTextEditor(aTargetElement)) {
if (this._handleDropToRichTextEditor(aSession, aTargetElement)) {
return true;
}
}
// Not handled - do something else?
return false;
}
/**************************************************************************
* Flock Rich Drag Drop Service Private Members
**************************************************************************/
flockRichDragDropService.prototype._getMessageFromTransferableWithFlavor =
function fRDDS_getMessageFromTransferableWithFlavor(aSubject, aFlavor) {
var message = {};
message.QueryInterface = function (aIID) {
if (aIID.equals(CI.flockIMessage) || aIID.equals(CI.nsISupports)) {
return this;
}
throw CR.NS_ERROR_NO_INTERFACE;
};
// Get content from transferable
var content = this._getFlavourData(aSubject, aFlavor);
if (!content) {
return message;
}
// Build message from content
var contentParts;
switch (aFlavor) {
case FLAVOR_MOZ_RDF:
var coop = CC["@flock.com/singleton;1"]
.getService(CI.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var item = coop.get(content);
message.subject = item.name;
if (item.isInstanceOf(coop.FeedItem)) {
message.body = this._getFlavourData(aSubject, FLAVOR_HTML);
} else {
message.body = item.description;
}
break;
case FLAVOR_FLOCK_MEDIA:
case FLAVOR_MOZ_URL:
contentParts = content.split("\n");
message.subject = contentParts[1];
message.body = contentParts[0];
break;
case FLAVOR_TEXT_CITE:
contentParts = content.split("\n");
message.subject = contentParts[2];
message.body = content;
break;
case FLAVOR_HTML_CITE:
message.subject = "";
message.body = content;
break;
case FLAVOR_UNICODE:
contentParts = content.split(": ");
// Can parse if the ": " separator doesn't occur more than once
if (contentParts.length == 2) {
message.subject = contentParts[0];
message.body = contentParts[1];
} else {
message.subject = "";
message.body = content;
}
break;
case FLAVOR_HTML:
message.subject = "";
message.body = content;
break;
}
if (!message.body) {
_logger.debug("The flavor '"+aFlavor+"' is unsupported by this method");
}
return message;
}
// Used code from viewPartialSource.js
flockRichDragDropService.prototype._selectionToHtml =
function fRDDS__selectionToHtml(aSelection) {
var inst = this;
/////////////////////////////////////////////////////////////////////////
// helper to get a path like FIXptr, but with an array
// instead of the "tumbler" notation
// see FIXptr:
// http://lists.w3.org/Archives/Public/www-xml-linking-comments/2001AprJun/att-0074/01-NOTE-FIXptr-20010425.htm
function getPath(ancestor, node) {
var n = node;
var p = n.parentNode;
if (n == ancestor || !p) {
return null;
}
var path = [];
if (!path) {
return null;
}
do {
for (var i = 0; i < p.childNodes.length; i++) {
if (p.childNodes.item(i) == n) {
path.push(i);
break;
}
}
n = p;
p = n.parentNode;
} while (n != ancestor && p);
return path;
};
function makeRelativeLinksAbsolute(aBaseUrl, aDOMNode) {
// This is a recursive method: bail if no tag name
if (!aDOMNode.tagName) {
return;
}
switch (aDOMNode.tagName.toLowerCase()) {
case "img":
var url = aDOMNode.getAttribute("src");
if (!url.match("http")) {
aDOMNode.setAttribute("src", inst._makeURLAbsolute(aBaseUrl, url));
}
break;
case "a":
var url = aDOMNode.getAttribute("href");
if (url && !url.match("http")) {
aDOMNode.setAttribute("href", inst._makeURLAbsolute(aBaseUrl, url));
}
break;
default:
break
}
if (aDOMNode.hasChildNodes()) {
var kids = aDOMNode.childNodes;
for (var i = 0; i < kids.length; i++) {
makeRelativeLinksAbsolute(aBaseUrl, kids[i]);
}
}
};
var range = aSelection.getRangeAt(0);
var ancestorContainer = range.commonAncestorContainer;
var doc = ancestorContainer.ownerDocument;
var startContainer = range.startContainer;
var endContainer = range.endContainer;
var startOffset = range.startOffset;
var endOffset = range.endOffset;
// let the ancestor be an element
if (ancestorContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
ancestorContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
{
ancestorContainer = ancestorContainer.parentNode;
}
// for selectAll, let's use the entire document, including <html>...</html>
// @see DocumentViewerImpl::SelectAll() for how selectAll is implemented
try {
if (ancestorContainer == doc.body) {
ancestorContainer = doc.documentElement;
}
} catch (ex) {
}
// each path is a "child sequence" (a.k.a. "tumbler") that
// descends from the ancestor down to the boundary point
var startPath = getPath(ancestorContainer, startContainer);
var endPath = getPath(ancestorContainer, endContainer);
// clone the fragment of interest and reset everything to be relative to it
// note: it is with the clone that we operate from now on
ancestorContainer = ancestorContainer.cloneNode(true);
startContainer = ancestorContainer;
endContainer = ancestorContainer;
var i;
for (i = startPath ? startPath.length-1 : -1; i >= 0; i--) {
startContainer = startContainer.childNodes.item(startPath[i]);
}
for (i = endPath ? endPath.length-1 : -1; i >= 0; i--) {
endContainer = endContainer.childNodes.item(endPath[i]);
}
// add special markers to record the extent of the selection
// note: |startOffset| and |endOffset| are interpreted either as
// offsets in the text data or as child indices (see the Range spec)
// (here, munging the end point first to keep the start point safe...)
var tmpNode;
if (endContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
endContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
{
// do some extra tweaks to try to avoid the view-source output to look like
// ...<tag>]... or ...]</tag>... (where ']' marks the end of selection).
// To get a neat output, the idea here is to remap the end point from:
// 1. ...<tag>]... to ...]<tag>...
// 2. ...]</tag>... to ...</tag>]...
if ((endOffset > 0 && endOffset < endContainer.data.length) ||
!endContainer.parentNode ||
!endContainer.parentNode.parentNode)
{
endContainer.insertData(endOffset, MARK_SELECTION_END);
} else {
tmpNode = doc.createTextNode(MARK_SELECTION_END);
endContainer = endContainer.parentNode;
if (endOffset == 0) {
endContainer.parentNode.insertBefore(tmpNode, endContainer);
} else {
endContainer.parentNode.insertBefore(tmpNode, endContainer.nextSibling);
}
}
} else {
tmpNode = doc.createTextNode(MARK_SELECTION_END);
endContainer.insertBefore(tmpNode, endContainer.childNodes.item(endOffset));
}
if (startContainer.nodeType == CI.nsIDOMNode.TEXT_NODE ||
startContainer.nodeType == CI.nsIDOMNode.CDATA_SECTION_NODE)
{
// do some extra tweaks to try to avoid the view-source output to look like
// ...<tag>[... or ...[</tag>... (where '[' marks the start of selection).
// To get a neat output, the idea here is to remap the start point from:
// 1. ...<tag>[... to ...[<tag>...
// 2. ...[</tag>... to ...</tag>[...
if ((startOffset > 0 && startOffset < startContainer.data.length) ||
!startContainer.parentNode ||
!startContainer.parentNode.parentNode ||
startContainer != startContainer.parentNode.lastChild)
{
startContainer.insertData(startOffset, MARK_SELECTION_START);
} else {
tmpNode = doc.createTextNode(MARK_SELECTION_START);
startContainer = startContainer.parentNode;
if (startOffset == 0) {
startContainer.parentNode.insertBefore(tmpNode, startContainer);
} else {
startContainer.parentNode.insertBefore(tmpNode,
startContainer.nextSibling);
}
}
} else {
tmpNode = doc.createTextNode(MARK_SELECTION_START);
startContainer.insertBefore(tmpNode,
startContainer.childNodes.item(startOffset));
}
// now extract, make url absolute and return the HTML source
tmpNode = doc.createElementNS(NS_XHTML, "div");
tmpNode.appendChild(ancestorContainer);
makeRelativeLinksAbsolute(doc.location, tmpNode);
return tmpNode.innerHTML;
}
flockRichDragDropService.prototype._makeURLAbsolute =
function fRDDS__makeURLAbsolute(aBase, aUrl) {
try {
var ioService = CC["@mozilla.org/network/io-service;1"]
.getService(CI.nsIIOService);
var baseURI = ioService.newURI(aBase, null, null);
return ioService.newURI(baseURI.resolve(aUrl), null, null).spec;
} catch (ex) {
// Special URLs throw exceptions, in this case we just return it "as is"
return aUrl;
}
}
flockRichDragDropService.prototype._makeHTMLCitation =
function fRDDS__makeHTMLCitation(aUrl, aTitle, aContent) {
var source = <p class="citation">
<cite>
<a href={aUrl}>{aTitle}</a>
</cite>
</p>;
// We don't use E4X here because it would escape "aContent"
var result = "<blockquote cite=" + aUrl + ">"
+ "<p>" + aContent + "</p>"
+ "</blockquote>"
+ source.toXMLString();
return result;
}
flockRichDragDropService.prototype._makeTextCitation =
function fRDDS__makeTextCitation(aUrl, aTitle, aContent) {
var result = aContent + "\n\n"
+ aTitle + "\n"
+ aUrl;
return result;
}
flockRichDragDropService.prototype._addTextFlavour =
function fRDDS__addTextFlavour(aTransferable,
aFlavour,
aTextData)
{
var supports = CC["@mozilla.org/supports-string;1"]
.createInstance(CI.nsISupportsString);
supports.data = aTextData;
aTransferable.addDataFlavor(aFlavour);
var length = supports.data.length * 2;
aTransferable.setTransferData(aFlavour, supports, length);
return aTransferable;
}
flockRichDragDropService.prototype._getImageTransferable =
function fRDDS__getImageTransferable(aImageUrl,
aImageTitle,
aWebPageUrl)
{
var result = CC["@mozilla.org/widget/transferable;1"]
.createInstance(CI.nsITransferable);
// text/x-moz-url
var urltext = ((aImageTitle.length) ? (aImageTitle + ":\n") : "")
+ aWebPageUrl;
this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
// text/x-flock-media
var text = aImageUrl + "\n" + aImageTitle;
this._addTextFlavour(result, FLAVOR_FLOCK_MEDIA, text);
// text/unicode
var text = ((aImageTitle.length) ? (aImageTitle + ": ") : "")
+ aImageUrl;
this._addTextFlavour(result, FLAVOR_UNICODE, text);
// text/html
var html = <a href={aWebPageUrl} title={aImageTitle}>
<img alt={aImageTitle} src={aImageUrl}/>
</a>;
this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
// text/x-flock-htmlcitation
var citation = this._makeHTMLCitation(aWebPageUrl, aImageTitle, html);
this._addTextFlavour(result, FLAVOR_HTML_CITE, citation);
return result;
}
flockRichDragDropService.prototype._getLinkTransferable =
function fRDDS__getLinkTransferable(aURL, aTitle) {
var result = CC["@mozilla.org/widget/transferable;1"]
.createInstance(CI.nsITransferable);
// text/x-moz-url
var urltext = aURL + "\n" + aTitle;
this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
// text/unicode
var text = aTitle + ": " + aURL;
this._addTextFlavour(result, FLAVOR_UNICODE, text);
// text/html
var html = <a href={aURL}>{aTitle}</a>;
this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
return result;
}
flockRichDragDropService.prototype._getSelectionTransferable =
function fRDDS__getSelectionTransferable(aURL, aTitle, aSelection) {
var result = CC["@mozilla.org/widget/transferable;1"]
.createInstance(CI.nsITransferable);
// text/x-flock-htmlcitation
var htmlCitation = this._makeHTMLCitation(aURL, aTitle, html)
this._addTextFlavour(result, FLAVOR_HTML_CITE, htmlCitation);
// text/x-flock-textcitation
var textCitation = this._makeTextCitation(aURL, aTitle, text)
this._addTextFlavour(result, FLAVOR_TEXT_CITE, textCitation);
// text/unicode
var text = aTitle + ": " + aSelection.toString();
this._addTextFlavour(result, FLAVOR_UNICODE, text);
// text/html
var html = this._selectionToHtml(aSelection);
this._addTextFlavour(result, FLAVOR_HTML, html);
return result;
}
flockRichDragDropService.prototype._getMediabarTransferable =
function fRDDS__getMediabarTransferable(aMedia, aTopUrl)
{
var result = CC["@mozilla.org/widget/transferable;1"]
.createInstance(CI.nsITransferable);
var title = aMedia.title.replace(/%20/g, " ");
var url = aMedia.webPageUrl;
var imageUrl = aMedia.midSizePhoto;
// text/x-moz-url
var urltext = ((title.length) ? (title + ":\n") : "") + aTopUrl;
this._addTextFlavour(result, FLAVOR_MOZ_URL, urltext);
// text/x-flock-media
var text = url + "\n" + title;
this._addTextFlavour(result, FLAVOR_FLOCK_MEDIA, text);
// text/unicode
var text = ((title.length) ? (title + ": ") : "") + url;
this._addTextFlavour(result, FLAVOR_UNICODE, text);
// text/html
var html;
if (eval(aMedia.is_video)) {
// video
html = aMedia.buildHTML();
this._addTextFlavour(result, FLAVOR_HTML, html);
} else {
// photo
html = <a href={url} title={title}>
<img alt={title} src={imageUrl}/>
</a>;
this._addTextFlavour(result, FLAVOR_HTML, html.toXMLString());
}
// text/x-flock-htmlcitation
var citation = this._makeHTMLCitation(aTopUrl, title, html);
this._addTextFlavour(result, FLAVOR_HTML_CITE, citation);
return result;
}
// Retrieves the flavour data from the transferable
flockRichDragDropService.prototype._getFlavourData =
function fRDDS__getFlavourData(aTransferable, aFlavor) {
if (!aTransferable || !aFlavor) {
return "";
}
var dataObj = {};
var len = {};
// If the flavor is not in the transferable, then this call will throw
try {
aTransferable.getTransferData(aFlavor, dataObj, len);
} catch (ex) {
_logger.debug("The flavor '"+aFlavor+"' is unsupported by this transferable");
return "";
}
return dataObj.value.QueryInterface(CI.nsISupportsString).data;
}
// Determine the appropriate action when dropping rich content onto a TEXTAREA
// element.
flockRichDragDropService.prototype._handleDropToTextArea =
function frDDS__handleDropToTextArea(aSession, aTextarea) {
if (!(aSession && aTextarea)) {
return false;
}
var catMgr = CC[FLOCK_CATEGORY_MANAGER_CONTRACT_ID]
.getService(CI.nsICategoryManager);
var svcEnum = catMgr.enumerateCategory(FLOCK_RICH_CONTENT_CATEGORY_ENTRY);
if (!svcEnum) {
return false;
}
// Get the various rich content flavours
var trans = this.getRichSelection(aSession);
// Find the appropriate supported service to drop the rich content on
while (svcEnum.hasMoreElements()) {
var entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString);
if (entry) {
var contractID = catMgr.getCategoryEntry(FLOCK_RICH_CONTENT_CATEGORY_ENTRY,
entry.data);
var service = CC[contractID].getService(CI.flockIRichContentDropHandler);
if (service.handleDrop(trans, aTextarea)) {
// Dropped the rich content on the appropriate supported service,
// no need to continue searching
return true;
}
}
}
// Could not find the appropriate supported service to drop the rich
// context on, drop uber-flav
var uberFlavour = this._getUberFlavour(trans);
if (uberFlavour) {
this._addToTextarea(uberFlavour, aTextarea);
return true;
}
// No uber-flavour either
return false;
}
// Determine the appropriate action when dropping rich content onto an element
// within a rich text editor
flockRichDragDropService.prototype._handleDropToRichTextEditor =
function frDDS__handleDropToRichTextEditor(aSession, aTargetElement) {
if (!(aSession && aTargetElement)) {
return false;
}
// Get the various rich content flavours
var transferable = this.getRichSelection(aSession);
if (!transferable) {
return false;
}
// Get rich content
var content = this._getFlavourData(transferable, FLAVOR_HTML);
if (!content || this._isRichVideoContent(content)) {
// If we couldn't get the rich content or it's a video, just get plain text
// "Rich textareas" used in mail clients cannot accept HTML OBJECT or
// EMBED tags
content = this._getFlavourData(transferable, FLAVOR_UNICODE);
content = content.replace(/: /g, ":<br />");
}
// Add it to the editor
if (content) {
this._addToRichTextEditor(content, aTargetElement);
return true;
}
// We have failed
return false;
}
// Check if the content is rich video content
flockRichDragDropService.prototype._isRichVideoContent =
function fRDDS__isRichVideoContent(aContent) {
// Rich video content will be made up of:
// 1) an EMBED tag or
// 2) an EMBED tag within an OBJECT tag
return aContent && (aContent.toLowerCase().indexOf("<embed ") > -1);
}
// Get the uber flavour with the desired richness
flockRichDragDropService.prototype._getUberFlavour =
function fRDDS__getUberFlavour(aTransferable, aType) {
if (!aTransferable) {
return "";
}
var uberFlavour = "";
var newline = "\n";
if (aType == "rich") {
newline = "<br />";
}
var link = this._getFlavourData(aTransferable, FLAVOR_UNICODE);
if (link) {
uberFlavour = flockGetString("common/sharing",
"flock.sharing.uberFlavour.link")
+ newline + link;
}
var content = this._getFlavourData(aTransferable, FLAVOR_HTML);
if (content) {
if (uberFlavour) {
uberFlavour += newline + newline;
}
uberFlavour += flockGetString("common/sharing",
"flock.sharing.uberFlavour.content")
+ newline + this._sanitizeHTMLContent(content);
}
return uberFlavour;
}
flockRichDragDropService.prototype._sanitizeHTMLContent =
function fRDDS__sanitizeHTMLContent(aContent) {
return aContent.replace(/&/g, "&");
}
flockRichDragDropService.prototype._isInRichTextEditor =
function fRDDS__isInRichTextEditor(aElement) {
return aElement.ownerDocument.designMode == "on";
}
// Add the content to the text area object
flockRichDragDropService.prototype._addToTextarea =
function fRDDS__addToTextArea(aContent, aTextarea) {
if (aContent && aTextarea) {
var caretPos = aTextarea.selectionEnd;
var currentValue = aTextarea.value;
var breadcrumb = (aTextarea.value.length == caretPos)
? this.getBreadcrumb()
: "";
aTextarea.value = currentValue.substring(0, caretPos)
+ aContent
+ currentValue.substring(caretPos)
+ breadcrumb;
}
}
// Add the content to the targeted elment in the rich text editor
flockRichDragDropService.prototype._addToRichTextEditor =
function fRDDS__addToRichTextEditor(aContent, aTargetElement) {
if (aContent && aTargetElement) {
var doc = aTargetElement.ownerDocument;
var targetName = aTargetElement.localName.toLowerCase();
// Create SPAN element containing content
var contentElement = doc.createElement("span");
contentElement.innerHTML = aContent;
if (targetName == "html" || targetName == "body") {
// Not any specific element within the body, so add at insertion point
doc.execCommand("insertHTML", false, aContent);
} else {
// Insert after target element
aTargetElement.parentNode.insertBefore(contentElement,
aTargetElement.nextSibling);
}
// Check for breadcrumb -- we don't want to add more than one
if (!doc.getElementById(FLOCK_BREADCRUMB_ID)) {
// Append the breadcrumb to the body
var breadcrumbElement = doc.createElement("span");
breadcrumbElement.setAttribute("id", FLOCK_BREADCRUMB_ID);
breadcrumbElement.innerHTML = this.getBreadcrumb("rich");
doc.body.appendChild(breadcrumbElement);
}
}
}
/**************************************************************************
* END Flock Rich Drag Drop Service Private Members
**************************************************************************/
/**************************************************************************
* END Flock Rich Drag Drop Service
**************************************************************************/
/**************************************************************************
* Helper Components
**************************************************************************/
const JS_SUBSCRIPT_LOADER_CONTRACTID = "@mozilla.org/moz/jssubscript-loader;1";
function loadSubScript(spec) {
var loader = CC[JS_SUBSCRIPT_LOADER_CONTRACTID]
.getService(CI.mozIJSSubScriptLoader);
var context = {};
loader.loadSubScript(spec, context);
return context;
}
function loadLibraryFromSpec(aSpec) {
var loader = CC[JS_SUBSCRIPT_LOADER_CONTRACTID]
.getService(CI.mozIJSSubScriptLoader);
loader.loadSubScript(aSpec);
}
loadLibraryFromSpec("chrome://flock/content/common/flocksafe.js");
/**************************************************************************
* XPCOM Support - Module Construction
**************************************************************************/
// Create array of components.
var componentArray = [flockRichDragDropService];
// Wrap the components in a module.
var module = new FlockXPCOMUtils.genericModule(MODULE_NAME, componentArray);
// Provide XPCOM with access to the module.
function NSGetModule(aCompMgr, aFileSpec) {
return module;
}
/**************************************************************************
* END XPCOM Support
**************************************************************************/